<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .wrap {
            margin-bottom: 40px;
        }
    </style>
</head>

<body>

    <div id="app">
        <!-- vue响应式和数组 -->

        <p>
            zhang: {{zhang.name}}---{{zhang.age}}----{{zhang.hobby}}
        </p>
        <p>
            <button @click="changeName">changeName</button>
            <button @click="changeAge">changeAge</button>
        </p>
        <p>
            <button @click="addProp">addProp</button>
            <button @click="editHobby">editHobby</button>
        </p>
        <p>
            <button @click="test">错误演示</button>
        </p>

        <p>list: {{list}}</p>
    </div>
</body>
<script>

    /* 
        Vue2的响应式本质依赖于Object.defineProperty(),对应data中挂载数据的键名绑定取值拦截和赋值拦截
        1. 如果直接对应属性名赋新值,可以被Vue响应式机制检测到
        2. 如果data属性的属性值是数组和对象, 直接修改数组和对象中数据, 不可以被Vue响应式机制检测到

        由于 JavaScript 的限制，Vue 不能检测数组和对象的变化  
            a. 其中 Vue已经做了一部分处理
            b. 还有一部分遗留问题  !!!!


        对于数组而言: 
            Vue 不能检测数组变化,为了解决这个问题,Vue将数组的方法分为变更方法和非变更方法分别做了不同处理
            1. 变更方法 => 调用该方法后会影响原数组的方法 (Vue 将被侦听的数组的变更方法进行了包裹，所以它们也将会触发视图更新)
                push()
                pop()
                shift()
                unshift()
                splice()
                sort()
                reverse()

            2. 非变更方法 => 调用该方法后不会影响原数组,而是返回新数组的方法
                slice()  concat()  map()  filter()  flat()

            Vue中数组遗留问题!!!
            Vue 不能检测以下数组的变动：
                当你利用索引直接设置一个数组项时，例如：vm.items[indexOfItem] = newValue
                当你修改数组的长度时，例如：vm.items.length = newLength


         对于对象而言:
            Vue 不能检测对象变化, 为了解决这个问题, Vue会检测data中挂载数据的类型,如果是对象类型, 会进行深度拦截(在初始化渲染阶段处理)
            Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化，所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的
            
            Vue 不能检测以下对象的变动：
                给对象新增属性 ( Vue 会在初始化实例时对 property 执行 getter/setter 转化,实例化对象创建完毕之后在新增就无法被Vue响应式检测到)

                解决方法:
                     this.$set(target,key,value);  // 此方法信息属性时会绑定数据劫持(getter/setter), 数据改变之后会被Vue响应式检测到

                     !! Vue 不允许动态添加根级响应式 property     在this.$data上新增属性


    
    */



    var vm = new Vue({
        el: "#app",
        data: {
            zhang:{
                name:"张三",
                age:18,
                // hobby:null,   // 就提前预留属性的位置
            },
        },
        methods: {
            changeName(){
                this.zhang.name = "李四";
            },
            changeAge(){
                this.zhang.age ++;
            },
            addProp(){
                //  Vue 会在初始化实例时对 property 执行 getter/setter 转化, 此代码点击时新增属性(此时Vue实例已经初始化完毕 )
                // this.zhang.hobby = ["sing","dance","rap"];
                // console.log(this.zhang);

                // 解决方法:
                // (1) 既然无法新增,就提前预留属性的位置

                // (2) 强制视图更新
                // this.zhang.hobby = ["sing","dance","rap"];
                // this.$forceUpdate();

                // (3)  Vue中提供了修改对象数据的方法 $set()  (也会被Vue响应式检测到) 
                this.$set(this.zhang,"hobby",["sing","dance","rap"]);
                console.log(this);
            },
            editHobby(){
                if(this.zhang.hobby){
                    this.zhang.hobby.push("basketball");
                }
            },
            test(){
                //  Vue 不允许动态添加根级响应式 property
                this.$set(this.$data,"list",[1,2,3]);
            }
        }

    })


    console.log(vm);

</script>

</html>